"""
认证服务
"""
from datetime import datetime, timedelta
from typing import Optional, List, Tuple
from tortoise.exceptions import DoesNotExist, IntegrityError
from fastapi import HTTPException, status, Request
from loguru import logger

from app.models.user import User, Role, Permission, UserSession
from app.schemas.auth import (
    UserCreate, UserUpdate, UserResponse, UserLogin, UserChangePassword,
    RoleCreate, RoleUpdate, RoleResponse,
    PermissionCreate, PermissionUpdate, PermissionResponse,
    Token, LoginResponse, UserSessionResponse
)
from app.utils.security import (
    verify_password, get_password_hash, create_access_token,
    generate_session_token
)
from app.core.config import settings


class AuthService:
    """认证服务类"""
    
    @staticmethod
    async def create_user(user_data: UserCreate) -> UserResponse:
        """创建用户"""
        try:
            # 检查用户名是否重复
            existing_user = await User.get_or_none(username=user_data.username)
            if existing_user:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="用户名已存在"
                )
            
            # 检查邮箱是否重复
            existing_email = await User.get_or_none(email=user_data.email)
            if existing_email:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="邮箱已存在"
                )
            
            # 创建用户
            user_dict = user_data.dict()
            password = user_dict.pop('password')
            user_dict['hashed_password'] = get_password_hash(password)
            
            user = await User.create(**user_dict)
            
            logger.info(f"创建用户成功: {user.username}")
            return UserResponse.from_orm(user)
            
        except IntegrityError as e:
            logger.error(f"创建用户失败，数据完整性错误: {e}")
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="数据完整性错误，请检查输入数据"
            )
        except Exception as e:
            logger.error(f"创建用户失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="创建用户失败"
            )
    
    @staticmethod
    async def authenticate_user(username: str, password: str) -> Optional[User]:
        """验证用户"""
        try:
            user = await User.get_or_none(username=username, is_active=True)
            if not user:
                return None
            
            if not verify_password(password, user.hashed_password):
                return None
            
            # 更新最后登录时间
            user.last_login = datetime.now()
            await user.save()
            
            return user
        except Exception as e:
            logger.error(f"用户验证失败: {e}")
            return None
    
    @staticmethod
    async def login(login_data: UserLogin, request: Request) -> LoginResponse:
        """用户登录"""
        try:
            # 验证用户
            user = await AuthService.authenticate_user(
                login_data.username, 
                login_data.password
            )
            
            if not user:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail="用户名或密码错误"
                )
            
            # 创建访问令牌
            access_token = create_access_token(
                data={"sub": str(user.id), "username": user.username}
            )
            
            # 创建用户会话
            session_token = generate_session_token()
            expires_at = datetime.now() + timedelta(minutes=settings.access_token_expire_minutes)
            
            session = await UserSession.create(
                user=user,
                session_token=session_token,
                ip_address=request.client.host if request.client else None,
                user_agent=request.headers.get("user-agent"),
                expires_at=expires_at
            )
            
            # 构建响应
            token = Token(
                access_token=access_token,
                token_type="bearer",
                expires_in=settings.access_token_expire_minutes * 60
            )
            
            user_response = UserResponse.from_orm(user)
            session_response = UserSessionResponse.from_orm(session)
            
            logger.info(f"用户登录成功: {user.username}")
            
            return LoginResponse(
                user=user_response,
                token=token,
                session=session_response
            )
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"用户登录失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="登录失败"
            )
    
    @staticmethod
    async def logout(user: User, session_token: Optional[str] = None) -> bool:
        """用户登出"""
        try:
            if session_token:
                # 使特定会话无效
                session = await UserSession.get_or_none(
                    user=user,
                    session_token=session_token,
                    is_valid=True
                )
                if session:
                    session.is_valid = False
                    await session.save()
            else:
                # 使所有会话无效
                await UserSession.filter(user=user, is_valid=True).update(is_valid=False)
            
            logger.info(f"用户登出成功: {user.username}")
            return True
            
        except Exception as e:
            logger.error(f"用户登出失败: {e}")
            return False
    
    @staticmethod
    async def change_password(
        user: User, 
        password_data: UserChangePassword
    ) -> bool:
        """修改密码"""
        try:
            # 验证旧密码
            if not verify_password(password_data.old_password, user.hashed_password):
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="旧密码错误"
                )
            
            # 更新密码
            user.hashed_password = get_password_hash(password_data.new_password)
            await user.save()
            
            # 使所有会话无效，强制重新登录
            await UserSession.filter(user=user, is_valid=True).update(is_valid=False)
            
            logger.info(f"用户修改密码成功: {user.username}")
            return True
            
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"修改密码失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="修改密码失败"
            )
    
    @staticmethod
    async def get_user(user_id: int) -> UserResponse:
        """获取用户详情"""
        try:
            user = await User.get(id=user_id)
            return UserResponse.from_orm(user)
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
    
    @staticmethod
    async def update_user(user_id: int, user_data: UserUpdate) -> UserResponse:
        """更新用户"""
        try:
            user = await User.get(id=user_id)
            
            # 检查邮箱是否重复
            if user_data.email and user_data.email != user.email:
                existing_email = await User.get_or_none(email=user_data.email)
                if existing_email:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="邮箱已存在"
                    )
            
            # 更新用户信息
            update_data = user_data.dict(exclude_unset=True)
            await user.update_from_dict(update_data)
            await user.save()
            
            logger.info(f"更新用户成功: {user.username}")
            return UserResponse.from_orm(user)
            
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"更新用户失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="更新用户失败"
            )
    
    @staticmethod
    async def delete_user(user_id: int) -> bool:
        """删除用户"""
        try:
            user = await User.get(id=user_id)
            
            # 软删除：设置为非活跃状态
            user.is_active = False
            await user.save()
            
            # 使所有会话无效
            await UserSession.filter(user=user, is_valid=True).update(is_valid=False)
            
            logger.info(f"删除用户成功: {user.username}")
            return True
            
        except DoesNotExist:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )
        except Exception as e:
            logger.error(f"删除用户失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="删除用户失败"
            )
    
    @staticmethod
    async def list_users(
        page: int = 1,
        size: int = 20,
        is_active: Optional[bool] = None,
        search: Optional[str] = None
    ) -> Tuple[List[UserResponse], int]:
        """获取用户列表"""
        try:
            # 构建查询
            query = User.all()
            
            # 按活跃状态筛选
            if is_active is not None:
                query = query.filter(is_active=is_active)
            
            # 搜索
            if search:
                query = query.filter(
                    username__icontains=search
                ).union(
                    User.filter(full_name__icontains=search)
                ).union(
                    User.filter(email__icontains=search)
                )
            
            # 获取总数
            total = await query.count()
            
            # 分页
            offset = (page - 1) * size
            users = await query.offset(offset).limit(size)
            
            # 转换为响应模式
            user_responses = [UserResponse.from_orm(user) for user in users]
            
            return user_responses, total
            
        except Exception as e:
            logger.error(f"获取用户列表失败: {e}")
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="获取用户列表失败"
            )
